package com.rtc.call.core

import android.content.Context
import android.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.eclipse.paho.android.service.MqttAndroidClient
import org.eclipse.paho.client.mqttv3.*
import java.util.*

/**
 * MQTT client for handling communication with the MQTT broker
 * This is used for "MQTT" step in the flow diagram
 */
class MqttClient(
    private val context: Context,
    private val coroutineScope: CoroutineScope,
    private val configManager: ConfigManager
) {
    private val TAG = "MqttClient"
    
    // Default MQTT server settings - should be configured based on actual server details
    private val serverUri = "tcp://mqtt.example.com:1883"
    private val clientId = "AgoraCall_${UUID.randomUUID()}"
    
    private var mqttClient: MqttAndroidClient? = null
    private var isConnected = false
    
    /**
     * Connect to the MQTT broker
     */
    fun connect(
        onMqttConnected: () -> Unit,
        onMqttDisconnected: () -> Unit
    ) {
        mqttClient = MqttAndroidClient(context, serverUri, clientId).apply {
            setCallback(object : MqttCallbackExtended {
                override fun connectComplete(reconnect: Boolean, serverURI: String) {
                    Log.d(TAG, "MQTT connection complete: $serverURI, reconnect: $reconnect")
                    this@MqttClient.isConnected = true
                    
                    // Subscribe to configuration topics
                    subscribeToTopics()
                    
                    onMqttConnected()
                }
                
                override fun connectionLost(cause: Throwable?) {
                    Log.e(TAG, "MQTT connection lost", cause)
                    this@MqttClient.isConnected = false
                    onMqttDisconnected()
                }
                
                override fun messageArrived(topic: String, message: MqttMessage) {
                    Log.d(TAG, "MQTT message arrived: $topic, ${String(message.payload)}")
                    handleMqttMessage(topic, message)
                }
                
                override fun deliveryComplete(token: IMqttDeliveryToken) {
                    Log.d(TAG, "MQTT delivery complete")
                }
            })
        }
        
        // Connect options
        val connectOptions = MqttConnectOptions().apply {
            isAutomaticReconnect = true
            isCleanSession = true
            connectionTimeout = 30
            keepAliveInterval = 60
        }
        
        try {
            mqttClient?.connect(connectOptions, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) {
                    Log.d(TAG, "MQTT connection success")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
                    Log.e(TAG, "MQTT connection failure", exception)
                    onMqttDisconnected()
                }
            })
        } catch (e: MqttException) {
            Log.e(TAG, "MQTT connection error", e)
            onMqttDisconnected()
        }
    }
    
    /**
     * Subscribe to configuration topics for various modes as per the flow diagram
     */
    private fun subscribeToTopics() {
        if (!isConnected || mqttClient == null) return
        
        val topics = arrayOf(
            "agora/call/config/turnon",
            "agora/call/config/nfcon",
            "agora/call/config/nfcoff",
            "agora/call/audio/volume"
        )
        
        val qos = IntArray(topics.size) { 1 } // QoS level 1 for all topics
        
        try {
            mqttClient?.subscribe(topics, qos, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) {
                    Log.d(TAG, "MQTT subscription success for topics: ${topics.joinToString()}")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
                    Log.e(TAG, "MQTT subscription failure", exception)
                }
            })
        } catch (e: MqttException) {
            Log.e(TAG, "MQTT subscribe error", e)
        }
    }
    
    /**
     * Handle received MQTT messages based on topics
     */
    private fun handleMqttMessage(topic: String, message: MqttMessage) {
        coroutineScope.launch {
            when (topic) {
                "agora/call/config/turnon" -> {
                    // Handle TURNON configuration
                    val configContent = String(message.payload)
                    // Process and save the configuration
                }
                "agora/call/config/nfcon" -> {
                    // Handle NFCON configuration
                    val configContent = String(message.payload)
                    // Process and save the configuration
                }
                "agora/call/config/nfcoff" -> {
                    // Handle NFCOFF configuration
                    val configContent = String(message.payload)
                    // Process and save the configuration
                }
                "agora/call/audio/volume" -> {
                    // Handle volume adjustment
                    val volumeValue = String(message.payload).toIntOrNull() ?: 0
                    // Adjust the audio volume
                }
            }
        }
    }
    
    /**
     * Publish a message to a topic
     */
    fun publish(topic: String, message: String, qos: Int = 1, retained: Boolean = false) {
        if (!isConnected || mqttClient == null) return
        
        try {
            val mqttMessage = MqttMessage().apply {
                payload = message.toByteArray()
                this.qos = qos
                isRetained = retained
            }
            
            mqttClient?.publish(topic, mqttMessage, null, object : IMqttActionListener {
                override fun onSuccess(asyncActionToken: IMqttToken) {
                    Log.d(TAG, "MQTT publish success: $topic")
                }
                
                override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
                    Log.e(TAG, "MQTT publish failure", exception)
                }
            })
        } catch (e: MqttException) {
            Log.e(TAG, "MQTT publish error", e)
        }
    }
    
    /**
     * Disconnect from MQTT broker
     */
    fun disconnect() {
        if (mqttClient?.isConnected == true) {
            try {
                mqttClient?.disconnect(null, object : IMqttActionListener {
                    override fun onSuccess(asyncActionToken: IMqttToken) {
                        Log.d(TAG, "MQTT disconnection success")
                        isConnected = false
                    }
                    
                    override fun onFailure(asyncActionToken: IMqttToken, exception: Throwable) {
                        Log.e(TAG, "MQTT disconnection failure", exception)
                    }
                })
            } catch (e: MqttException) {
                Log.e(TAG, "MQTT disconnect error", e)
            } finally {
                mqttClient?.close()
                mqttClient = null
            }
        }
    }
} 